package com.pomelo.base.core.config;

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * RestTemplate配置
 *
 * @author biankudingcha
 * @date: 2021-07-31
 * @since 0.5.0
 */
@Configuration
public class RestTemplateConfig {

    /**
     * 整个连接池的最大连接数
     */
    @Value("${pomelo.httpPool.maxTotal:20}")
    private int maxTotal;

    /**
     * 是每个route默认的最大连接数
     */
    @Value("${pomelo.httpPool.defaultMaxPerRoute:20}")
    private int defaultMaxPerRoute;

    /**
     * 设置连接超时时间,单位毫秒
     */
    @Value("${pomelo.httpPool.connectTimeout:10000}")
    private int connectTimeout;

    /**
     * 单位毫秒,从连接池中获取连接的超时时间，超时间未拿到可用连接，会抛出org.apache.http.conn.ConnectionPoolTimeoutException
     */
    @Value("${pomelo.httpPool.connectionRequestTimeout:10000}")
    private int connectionRequestTimeout;

    /**
     * 请求获取数据的超时时间，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
     */
    @Value("${pomelo.httpPool.socketTimeout:60000}")
    private int socketTimeout;

    /**
     * 用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间，如果超过，释放socket重新建立
     */
    @Value("${pomelo.httpPool.validateAfterInactivity:2000}")
    private int validateAfterInactivity;

    /**
     * RestTemplate
     *
     * @return RestTemplate
     */
    @Bean
    public RestTemplate restTemplate() {
        // return new RestTemplate(httpRequestFactory());
        RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(httpRequestFactory()));
        return restTemplate;
    }

    /**
     * ClientHttpRequestFactory
     *
     * @return ClientHttpRequestFactory
     */
    @Bean
    public ClientHttpRequestFactory httpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

    /**
     * HttpClient
     *
     * @return HttpClient
     */
    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", SSLConnectionSocketFactory.getSocketFactory()).build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        connectionManager.setMaxTotal(maxTotal);
        connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
        connectionManager.setValidateAfterInactivity(validateAfterInactivity);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout)
            .setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout).build();
        return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager)
            .build();
    }
}
